import 'dart:convert';

import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';

import 'api_interceptor.dart';
import 'api_method.dart';

class Api {
  static String base = '';

  static Duration timeout = const Duration(seconds: 60);

  static Map<String, dynamic> headers = {'content-type': 'application/json'};

  static BaseOptions option = BaseOptions(
    sendTimeout: timeout.inMilliseconds,
    connectTimeout: timeout.inMilliseconds,
    receiveTimeout: timeout.inMilliseconds,
    headers: headers,
  );

  static final Dio dio = Dio(option)..interceptors.add(ApiInterceptor());

  /// get请求
  static Future<T?> getData<T>({
    String? base,
    String? url,
    Map<String, dynamic>? params,
    T? Function(dynamic json)? convertBuilder,
  }) async {
    return requestData<T>(
      base: base,
      url: url,
      method: ApiMethod.get,
      params: params,
      convertBuilder: convertBuilder,
    );
  }

  /// get请求
  static Future<Map<String, dynamic>> get({
    String? base,
    String? url,
    Map<String, dynamic>? params,
  }) async {
    return request(
      base: base,
      url: url,
      method: ApiMethod.get,
      params: params,
    );
  }

  /// post请求
  static Future<T?> postData<T>({
    String? base,
    String? url,
    Map<String, dynamic>? params,
    data,
    T? Function(dynamic json)? convertBuilder,
  }) async {
    return requestData(
      base: base,
      url: url,
      method: ApiMethod.post,
      params: params,
      data: data,
      convertBuilder: convertBuilder,
    );
  }

  /// post请求
  static Future<Map<String, dynamic>> post({
    String? base,
    String? url,
    Map<String, dynamic>? params,
    data,
  }) async {
    return request(
      base: base,
      url: url,
      method: ApiMethod.post,
      params: params,
      data: data,
    );
  }

  static Future<T?> requestData<T>({
    String? base,
    String? url,
    ApiMethod? method,
    Map<String, dynamic>? headers,
    Map<String, dynamic>? params,
    data,
    T? Function(dynamic json)? convertBuilder,
  }) async {
    final map = await request(
      base: base,
      url: url,
      method: method,
      headers: headers,
      params: params,
      data: data,
    );
    return convertBuilder == null ? null : convertBuilder(map);
  }

  static Future<Map<String, dynamic>> request({
    String? base,
    String? url,
    ApiMethod? method,
    Map<String, dynamic>? headers,
    Map<String, dynamic>? params,
    data,
  }) async {
    try {
      final response = await requestResponse(
          base: base,
          url: url,
          method: method,
          headers: headers,
          params: params,
          data: data);
      Map<String, dynamic> result;
      if (response.data is Map) {
        result = response.data;
      } else if (response.data is String) {
        final json = jsonDecode(response.data);
        if (json is Map<String, dynamic>) {
          result = json;
        } else {
          result = {
            'data': json,
            'message': response.statusMessage ?? '',
            'code': response.statusCode,
          };
        }
      } else {
        result = {
          'data': response.data,
          'message': response.statusMessage ?? '',
          'code': response.statusCode,
        };
      }
      return result;
    } catch (e) {
      return {'message': e.toString(), 'code': 0};
    }
  }

  static Future<Response> requestResponse({
    String? base,
    String? url,
    ApiMethod? method,
    Map<String, dynamic>? headers,
    Map<String, dynamic>? params,
    data,
  }) async {
    String baseUrl = base ?? Api.base;
    url = url ?? '';
    method = method ?? ApiMethod.get;
    params = params ?? {};
    try {
      dio.options.baseUrl = baseUrl;
      headers ??= Api.headers;
      dio.options.headers = headers;

      if (dio.httpClientAdapter is DefaultHttpClientAdapter) {
        (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
            (client) {
          client.badCertificateCallback = (cert, host, port) {
            return true;
          };
          return client;
        };
      }

      Response resp;
      switch (method) {
        case ApiMethod.get:
          {
            resp = await dio.get(url, queryParameters: params);
            break;
          }
        case ApiMethod.post:
          {
            if (data == null) {
              resp = await dio.post(url, data: params);
            } else {
              resp = await dio.post(url, queryParameters: params, data: data);
            }
            break;
          }
        default:
          {
            resp = await dio.request(
              url,
              queryParameters: params,
              data: data,
              options: Options(
                method: method.name,
                headers: option.headers,
              ),
            );
          }
      }
      return resp;
    } catch (error) {
      if (error is DioError) {
        return Response(
          data: error.response?.data,
          statusCode: error.response?.statusCode,
          statusMessage: error.error.toString(),
          requestOptions: error.requestOptions,
        );
      } else {
        return Response(
          statusCode: 0,
          statusMessage: error.toString(),
          requestOptions: RequestOptions(
            baseUrl: baseUrl,
            path: url,
            method: method.name,
            headers: headers,
            queryParameters: params,
            data: data,
          ),
        );
      }
    }
  }
}
